home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
printing
/
rlpr-1.000
/
rlpr-1
/
rlpr-1.13
/
rlprd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-30
|
7KB
|
224 lines
/* filename: rlprd.c
* project: rlpr
* author: meem -- meem@sherilyn.wustl.edu
* version: $Id: rlprd.c,v 1.6 1996/06/01 02:45:28 meem Exp $
* contents: daemon which does "reflecting" of messages from nonprivileged
* to priviledged ports
*
* Time-stamp: <1996/05/31 21:44 -- meem@sherilyn.wustl.edu>
*/
/* copyright (c) 1996 meem, meem@gnu.ai.mit.edu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <sys/types.h> /* for pid_t */
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h> /* got gethostbyname() */
#include <sys/time.h> /* select() and macros */
#include <sys/stat.h> /* for umask() */
#include <unistd.h> /* for setsid() */
#include <string.h> /* for strerror() */
#include <syslog.h> /* logging facilities */
#include <errno.h>
#include <stdio.h> /* BUFSIZ */
#include <sys/socket.h> /* for bind(), connect(), etc */
#include <netinet/in.h> /* for sockaddr_in */
#include <sys/wait.h>
#include <stdarg.h>
#include "rlpr-common.h"
/* TO DO: more robust signal handling...!
*/
/* function prototypes */
void daemon_init(void);
void rlprd_fatal(char *function, ...);
void reapchild(int unused);
const char * inc_host(struct sockaddr_in *sin);
int main(int argc, char *argv[]) {
struct hostent *hp;
struct sockaddr_in sin_in; /* where we will listen */
struct sockaddr_in sin_out; /* our projected identity (to lpd) */
struct sockaddr_in sin_lpd; /* the connection we will send to lpd */
struct sockaddr_in sin_from; /* the connection that came in */
int inc_rlprd, sd_in, out_lpd;/* socket descriptors */
int sin_fromlen; /* the length of the incoming descriptor */
int nc, nfds; /* data moved in read/write */
char buf[BUFSIZ]; /* for moving data */
char printhost[MAXHOSTNAMELEN]; /* name of printhost */
pid_t pid; /* for fork() */
fd_set readfds; /* for select() */
int i; /* dummy variable */
int c;
name = *argv;
daemon_init();
get_local_hostname(); /* sets global variable */
if (!(hp = gethostbyname(local_hostname)))
rlprd_fatal("gethostbyname on %s", local_hostname);
if ((sd_in = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* 0 == auto proto config */
rlprd_fatal("socket");
/* zero out structs to get the unused part zeroed */
memset(&sin_in, 0, sizeof(sin_in));
memset(&sin_out, 0, sizeof(sin_out));
memset(&sin_lpd, 0, sizeof(sin_lpd));
sin_in.sin_family = sin_out.sin_family = sin_lpd.sin_family = AF_INET;
memcpy(&sin_in.sin_addr, hp->h_addr, hp->h_length);
memcpy(&sin_out.sin_addr, hp->h_addr, hp->h_length);
sin_in.sin_port = htons(RLPRD_TO_NUM);
sin_lpd.sin_port = htons(LPD_TO_NUM);
if (bind(sd_in, (struct sockaddr *) &sin_in, sizeof(sin_in)) < 0) {
if (errno == EADDRINUSE)
syslog(LOG_WARNING, "port %i in use: is %s already running?", RLPRD_TO_NUM, name);
else
syslog(LOG_WARNING, "bind to port %i failed: %m", RLPRD_TO_NUM);
exit(1);
}
listen(sd_in, 5); /* don't rely on more than 5 */
signal(SIGCHLD, reapchild);
while (1) {
if ((inc_rlprd = accept(sd_in, (struct sockaddr *) &sin_from, &sin_fromlen)) < 0)
if (errno != EINTR) syslog(LOG_WARNING, "accept: %m");
else continue;
if ((pid = fork()) < 0) rlprd_fatal("fork");
else if (!pid) {
/* CHILD */
signal(SIGCHLD, SIG_IGN);
i = 0;
do
if (read(inc_rlprd, &printhost[i], 1) < 0)
rlprd_fatal("unable to read proxy hostname");
while (printhost[i++] != '\n');
printhost[--i] = '\0';
syslog(LOG_INFO,"proxy from %s to %s", inc_host(&sin_from), printhost);
/* bind our local socket so we come from a privileged port */
if ((out_lpd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
rlprd_fatal("socket");
for (i = LO_LPD_FROM_NUM; i <= HI_LPD_FROM_NUM; i++) {
sin_out.sin_port = htons(i);
if (bind(out_lpd, (struct sockaddr *) &sin_out, sizeof(sin_out)) >= 0)
break;
}
if (i > HI_LPD_FROM_NUM) { /* didn't get a port */
syslog(LOG_WARNING, "bind to ports %i-%i: %m",
LO_LPD_FROM_NUM, HI_LPD_FROM_NUM);
exit(1);
}
/* fill in remaining part of sin_lpd struct with printhost */
if (!(hp = gethostbyname(printhost)))
rlprd_fatal("gethostbyname on printhost");
memcpy(&sin_lpd.sin_addr, hp->h_addr, hp->h_length);
if (connect(out_lpd, (struct sockaddr *) &sin_lpd, sizeof(sin_lpd)) < 0)
rlprd_fatal("connect");
while (1) { /* conversation loop */
FD_ZERO(&readfds); /* initialize fds structure */
FD_SET(inc_rlprd, &readfds);
FD_SET(out_lpd, &readfds);
if ((nfds = select(16, &readfds, NULL, NULL, NULL)) < 0) /* is 16 right here!? */
rlprd_fatal("select");
if (nfds) {
if (FD_ISSET(inc_rlprd, &readfds)) { /* data from rlpr client */
if ((nc = read(inc_rlprd, buf, sizeof(buf))) < 0)
rlprd_fatal("read1");
else if (!nc) break;
else write(out_lpd, buf, nc);
}
if (FD_ISSET(out_lpd, &readfds)) { /* data from lpd server */
if ((nc = read(out_lpd, buf, sizeof(buf))) < 0)
rlprd_fatal("read2");
else if (!nc) break;
else write(inc_rlprd, buf, nc);
}
}
}
exit(0);
}
/* PARENT */
close(inc_rlprd);
}
exit(0);
}
void daemon_init(void) {
pid_t pid;
/* make sure euid == root */
if (geteuid() != 0) {
fprintf(stderr, "%s must be run root or setuid root!\n", name);
exit(1);
}
openlog("rlprd", LOG_PID, LOG_LPR);
if ((pid = fork()) < 0) rlprd_fatal("fork");
else if (pid) exit(0); /* kill off parent */
/* CHILD */
setsid(); /* now unique session, PGID, no ctty */
chdir("/"); /* in case we were on a mounted partition */
umask(0); /* clear file mode creation mask */
}
const char * inc_host(struct sockaddr_in *sin) {
struct hostent *hp;
hp = gethostbyaddr((char *) &sin->sin_addr,
sizeof(struct in_addr), sin->sin_family);
if (!hp) rlprd_fatal("gethostbyaddr");
return hp->h_name;
}
void reapchild(int unused) {
int olderrno = errno;
while (waitpid( -1, NULL, WNOHANG) > 0) /* NULL BODY */;
signal(SIGCHLD, reapchild);
errno = olderrno;
}
void rlprd_fatal(char *fmt, ...) {
char buf[BUFSIZ];
va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
strcat(buf, ": %m");
syslog(LOG_ERR, buf);
va_end(ap);
exit(1);
}